/*
 * Copyright (C) 2010 Johan Waldeback
 *  
 * This file is part of the OpenFMS project (http://www.openfms-project.org)
 * 
 * OpenFMS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "InputViewerFrame.h"
#include "ChannelCtrl.h"
#include <wx/wx.h>

using namespace OpenFms;

/**
 * InputViewerFrame constructor
 *
 * Setup the initial apperance of the dialog.
 */
InputViewerFrame::InputViewerFrame( const wxString &title ) : 
	wxFrame(NULL, wxID_ANY, title )
{
	wxPanel *panel = new wxPanel(this);
	wxBoxSizer *editSizer = new wxBoxSizer(wxHORIZONTAL);
	editSizer->Add( new wxStaticText( panel, wxID_ANY, "Input controler:") );
	editSizer->Add( new wxTextCtrl( panel, ID_EDIT, "EskyInput.dll"), 1 );
	editSizer->Add( new wxButton( panel, ID_BROWSE, "Browse..."));
	editSizer->Add( new wxButton( panel, ID_LOAD, "Load"));

	//
	// create a grid with m_nChannelBars vertical bars in it
	//
	wxFlexGridSizer *grid = new wxFlexGridSizer( m_nChannelBars, 5, 5 );
	for( int i=0; i<m_nChannelBars; ++i ) {
		grid->Add( new wxStaticText( panel, wxID_ANY, wxT("CH X")) );
	}
	for( int i=0; i<m_nChannelBars; ++i ) {
		grid->Add( new ChannelCtrl( panel, ID_FIRSTBAR + i ) );
	}

	wxBoxSizer *vbox = new wxBoxSizer(wxVERTICAL);
	vbox->Add( editSizer );
	vbox->Add( grid );
	panel->SetSizerAndFit(vbox);
	this->Fit();
	
	//
	// Setup timer
	//
	m_timer = new wxTimer( this, ID_TIMER );
	if( m_timer ) {
		m_timer->Start(100);
	}

	//
	// 	Make connections
	//
	Connect( ID_BROWSE, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(InputViewerFrame::onBrowse) );
	Connect( ID_LOAD, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(InputViewerFrame::onLoad) );
	Connect( ID_TIMER,  wxEVT_TIMER, wxTimerEventHandler(InputViewerFrame::onTimer) );

	//DEBUG
	// todo: remove
	for( int i=0; i<m_nChannelBars; ++i ) {
		this->setBar( i, static_cast<float>( sinf(i)));
	}
}

/**
 * InputViewerFrame destructor
 */
InputViewerFrame::~InputViewerFrame()
{
	if(m_timer) delete m_timer;
}

/**
 * Callback function - called when the Browse button is pressed.
 *
 * Opens a file browser dialog and copies the selected filename to the edit control.
 */
void InputViewerFrame::onBrowse( wxCommandEvent &evt )
{
	wxFileDialog openFileDialog(this);
	if( openFileDialog.ShowModal() == wxID_OK ) {
		wxString filename = openFileDialog.GetPath();
		wxTextCtrl *ctrl = reinterpret_cast<wxTextCtrl *>(this->FindWindowById(ID_EDIT, this));
		if( ctrl ) {
			ctrl->SetLabel(filename);
		}
	}
}

/**
 * Callback function - called when the Load button is pressed.
 *
 * Loads the input driver specified in the edit control.
 */
void InputViewerFrame::onLoad( wxCommandEvent &evt )
{
	//
	// Get the filename from the edit box
	//
	wxTextCtrl *ctrl = reinterpret_cast<wxTextCtrl *>(this->FindWindowById(ID_EDIT, this));
	if( ctrl == NULL  ) {
		wxMessageBox(wxT("ERROR: Unable to find window ID_EDIT"));
		return ;
	}
	wxString filename = ctrl->GetLabel();

	//
	//
	//
	// todo: is this the right way to do it?
	if( m_input.loadLibrary(reinterpret_cast<const TCHAR *>(filename.wc_str())) == false ){
		wxMessageBox(filename, wxT("Load failed"));
	} else if ( m_input.createDevice() == false ) {
		wxMessageBox(filename, wxT("Create failed"));
	}
	/*else {
		wxMessageBox(filename, wxT("Load OK"));
	}*/
}

/**
 * Sets the value of a bar
 * @param bar Zero-based index of which bar to assign value to.
 * @param value Value to assign to the specified bar.
 */
void InputViewerFrame::setBar( size_t bar, float value )
{
	// check input values
	assert( bar >= 0 ) ;
	assert( bar < m_nChannelBars );
	if( bar < 0  || bar >= m_nChannelBars ) return ;

	// find bar
	ChannelCtrl *gauge = reinterpret_cast<ChannelCtrl *>(this->FindWindowById(ID_FIRSTBAR+bar, this));
	if( gauge == NULL ) return;

	// set value
	gauge->setValue(value);
}

/**
 * Callback value - called on each timer event
 *
 * Captures the loaded input device and updates all bars.
 */
void InputViewerFrame::onTimer( wxTimerEvent &evt )
{
	// only do something if a module is loaded
	if(m_input.isLoaded()) {
		
		// Capture inputs
		float channels[m_nChannelBars];
		m_input.capture( channels, 0, m_nChannelBars );

		// copy chanel data to the bars
		for( size_t i=0; i< m_nChannelBars; ++i ) {
			setBar(i, channels[i]);
		}
	}
	// todo: else gray out bars
}